//
//  KLPeerLocal.m
//  WebRTCDemo_iOS
//
//  Created by szblsx2 on 2020/3/5.
//  Copyright © 2020 szblsx2. All rights reserved.
//

#import "KLPeerLocal.h"
#import "KLAppDefine.h"
#import "KLClient.h"

@interface KLPeerLocal ()<RTCPeerConnectionDelegate>
//音频track
@property (nonatomic, strong) RTCAudioTrack *audioTrack;
//视频track
@property (nonatomic, strong) RTCVideoTrack *videoTrack;
//本地连接对象
@property (nonatomic, strong) RTCPeerConnection *mPeerConnection;
//媒体采集器
@property (nonatomic, strong) RTCCameraVideoCapturer *mVideoCapturer;
//工厂对象(上行传入)
@property (nonatomic, weak) RTCPeerConnectionFactory *mPeerConnectionFactory;
//信令对象(上行传入)
@property (nonatomic, weak) KLClient *mKLClient;
//ice服务器地址(上行传入)
@property (nonatomic, weak) NSArray <RTCIceServer *> *iceServers;
//ice收集状态 yes代表收集完成
@property (nonatomic, assign) BOOL bSendSdp;
//ice地址集合
@property (nonatomic, strong) NSMutableArray *mIceCandidates;
//视频流sender
@property (nonatomic, strong) RTCRtpSender *localViewSender;

@end

@implementation KLPeerLocal
{
    BOOL _usingFrontCamera;
}

/**初始化PeerLocal*/
- (instancetype)initWithClient:(KLClient *)client
                       factory:(RTCPeerConnectionFactory *)factory
                    iceServers:(NSArray<RTCIceServer *> *)iceServers
{
    if (self = [super init]) {
        _mKLClient = client;
        _mPeerConnectionFactory = factory;
        _iceServers = iceServers;
        _roomId = @"";
        _streamId = @"";
        _usingFrontCamera = YES;
    }
    return self;
}

/**初始化音视频采集*/
- (void)initCapturer
{
    [self createAudioTrack];
    [self createVideoTrack];
}

/**停止音视频采集*/
- (void)freeCapture
{
    if (_mVideoCapturer) {
        [_mVideoCapturer stopCapture];
        _mVideoCapturer = nil;
    }
}

/**创建PeerConnection*/
- (void)initPeerConnection
{
    if (!_mPeerConnection || _mPeerConnection.connectionState != RTCPeerConnectionStateConnected) {
        RTCConfiguration *configuration = [[RTCConfiguration alloc] init];
        configuration.iceServers = self.iceServers;
        configuration.disableIPV6 = YES;
        configuration.activeResetSrtpParams = YES;
        configuration.sdpSemantics = RTCSdpSemanticsUnifiedPlan;
        configuration.bundlePolicy = RTCBundlePolicyMaxBundle;
        configuration.tcpCandidatePolicy = RTCTcpCandidatePolicyDisabled;
        self.mPeerConnection = [self.mPeerConnectionFactory peerConnectionWithConfiguration:configuration constraints:[self defaultConstraint] delegate:self];
        //添加音视频track
        NSArray<NSString*> *mediaStreamLabels = @[@"ARDAMS"];
        [self.mPeerConnection addTrack:self.audioTrack streamIds:mediaStreamLabels];
        [self.mPeerConnection addTrack:self.videoTrack streamIds:mediaStreamLabels];
        //查找视频流sender
        [self.mPeerConnection.senders enumerateObjectsUsingBlock:^(RTCRtpSender * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
            if ([obj.track.kind isEqualToString:VIDEO_TRACK_TYPE]) {
                _localViewSender = obj;
            }
        }];
    }
}

/**删除PeerConnection*/
- (void)freePeerConnection
{
    _bSendSdp = NO;
    [_mIceCandidates removeAllObjects];
    if (_audioTrack) {
        _audioTrack = nil;
    }
    if (_videoTrack) {
        _videoTrack = nil;
    }
    if (_mPeerConnection) {
        [_mPeerConnection close];
        _mPeerConnection = nil;
    }
}

/**创建offer SDP*/
- (void)createOffer
{
    if (!_mPeerConnection) {
        return;
    }
    [_mPeerConnection offerForConstraints:[self defaultConstraint] completionHandler:^(RTCSessionDescription * _Nullable sdp, NSError * _Nullable error) {
        if (error) {
            NSLog(@"creatOffer error : %@",error);
            return;
        }
        __weak __typeof(self) ws = self;
        [self->_mPeerConnection setLocalDescription:sdp completionHandler:^(NSError * _Nullable error) {
            if (error) {
                NSLog(@"setLocal error : %@",error);
                return;
            }
            //发送publish到信令服务器
            ws.bSendSdp = YES;
            [ws.mKLClient sendPublish:ws.roomId sdp:ws.mPeerConnection.localDescription.sdp bScreen:false];
            //设置视频参数
            [ws setVideoBitrate];
        }];
    }];
}

/**接收到远端answer SDP处理*/
- (void)onRemoteDescription:(RTCSessionDescription *)sessionDescription
{
    [self.mPeerConnection setRemoteDescription:sessionDescription completionHandler:^(NSError * _Nullable error) {
        if (error) {
            NSLog(@"本端setRemoteDescription error %@",error);
        }else{
            NSLog(@"本端setRemoteDescription success");
        }
    }];
}

/**发送停止推流*/
- (void)sendUnPublish
{
    [self.mKLClient sendUnpublish:self.roomId mid:self.streamId];
}

/**是否打开摄像头*/
- (void)turnOnCamera:(BOOL)open
{
    if (_videoTrack) {
        _videoTrack.isEnabled = open;
    }
}

/**切换前后置摄像头*/
- (void)switchCamera
{
    _usingFrontCamera = !_usingFrontCamera;
    //先停止采集
    if (_mVideoCapturer) {
        [_mVideoCapturer stopCapture];
    }
    //切换设备采集视频流
    [self createVideoTrack];
}

/**是否打开麦克风*/
- (void)turnOnMicrophone:(BOOL)open
{
    if (_audioTrack) {
        _audioTrack.isEnabled = open;
    }
}

/**是否开启扬声器*/
- (void)whetherToOpenLoudspeaker:(BOOL)open
{
    if (open) {
        [[UIDevice currentDevice] setProximityMonitoringEnabled:NO];
        //此方法设置之后，如果此时插入耳机在拔掉。播放的声音会从听筒输出，而不是回到扬声器
//      [[AVAudioSession sharedInstance] overrideOutputAudioPort:AVAudioSessionPortOverrideSpeaker error:nil];
        //此方法设置之后，始终输出到扬声器，而不是其他接收器 如果此时插入耳机在拔掉。播放的声音会从扬声器输出
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionDefaultToSpeaker error:nil];
    }else{
        [[UIDevice currentDevice] setProximityMonitoringEnabled:YES];
        [[AVAudioSession sharedInstance] setCategory:AVAudioSessionCategoryPlayAndRecord withOptions:AVAudioSessionCategoryOptionInterruptSpokenAudioAndMixWithOthers error:nil];
    }
    
}


#pragma mark - RTCPeerConnectionDelegate

- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeSignalingState:(RTCSignalingState)stateChanged
{
    NSLog(@"");
}

- (void)peerConnection:(RTCPeerConnection *)peerConnection didAddStream:(RTCMediaStream *)stream
{
    NSLog(@"");
}

- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveStream:(RTCMediaStream *)stream
{
    NSLog(@"");
}

- (void)peerConnectionShouldNegotiate:(RTCPeerConnection *)peerConnection
{
    NSLog(@"");
}

- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceConnectionState:(RTCIceConnectionState)newState
{
    NSLog(@"");
    
    if (newState == RTCIceConnectionStateConnected) {
        NSDictionary *responeDict = @{@"event":@(1001),@"code":@(200),@"mid":_streamId,@"roomId":_roomId};
        if (self.eventHandleBlock) {
            self.eventHandleBlock(responeDict);
        }
    }

    if (newState == RTCIceConnectionStateDisconnected || newState == RTCIceConnectionStateFailed) {
        NSDictionary *responeDict = @{@"event":@(1001),@"code":@(201),@"mid":_streamId,@"roomId":_roomId};
        if (self.eventHandleBlock) {
            self.eventHandleBlock(responeDict);
        }
    }
}

/**ICEcandidate收集状态变化*/
- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeIceGatheringState:(RTCIceGatheringState)newState
{
    if (newState == RTCIceGatheringStateComplete && _bSendSdp) {
        NSLog(@"IceCandidate收集完成");
        for (RTCIceCandidate *candidate in self.mIceCandidates) {
            [self sendLocalIceCandidate:candidate];
        }
    }
}

/**获取到新的ICEcandidate*/
- (void)peerConnection:(RTCPeerConnection *)peerConnection didGenerateIceCandidate:(RTCIceCandidate *)candidate
{
    NSLog(@"IceCandidate收集 : %@",candidate.sdp);
    [self.mIceCandidates addObject:candidate];
}

- (void)peerConnection:(RTCPeerConnection *)peerConnection didRemoveIceCandidates:(NSArray<RTCIceCandidate *> *)candidates
{
    NSLog(@"");
}

- (void)peerConnection:(RTCPeerConnection *)peerConnection didOpenDataChannel:(RTCDataChannel *)dataChannel
{
    NSLog(@"");
}

- (void)peerConnection:(RTCPeerConnection *)peerConnection didChangeConnectionState:(RTCPeerConnectionState)newState
{
    NSLog(@"");

    if (newState == RTCPeerConnectionStateConnected) {
        NSDictionary *responeDict = @{@"event":@(1002),@"code":@(200),@"mid":_streamId,@"roomId":_roomId};
        if (self.eventHandleBlock) {
            self.eventHandleBlock(responeDict);
        }
    }

    if (newState == RTCPeerConnectionStateDisconnected || newState == RTCPeerConnectionStateClosed) {
        NSDictionary *responeDict = @{@"event" : @(1002),@"code":@(201),@"mid":_streamId,@"roomId":_roomId};
        if (self.eventHandleBlock) {
            self.eventHandleBlock(responeDict);
        }
    }
}

#pragma mark - Private Method

/**创建本地音频Track*/
- (void)createAudioTrack
{
    // 音频功能开关
    RTCMediaConstraints *audioConstraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:@{AUDIO_ECHO_CANCELLATION_CONSTRAINT: @"true",
                                                                                                        AUDIO_AUTO_GAIN_CONTROL_CONSTRAINT: @"true",
                                                                                                        AUDIO_HIGH_PASS_FILTER_CONSTRAINT : @"true",
                                                                                                        AUDIO_NOISE_SUPPRESSION_CONSTRAINT: @"true"} optionalConstraints:nil];
    // 创建Track
    RTCAudioSource *mAudioSource = [self.mPeerConnectionFactory audioSourceWithConstraints:audioConstraints];
    self.audioTrack = [self.mPeerConnectionFactory audioTrackWithSource:mAudioSource trackId:AUDIO_TRACK_ID];
    self.audioTrack.isEnabled = YES;
}

/**创建本地视频Track*/
- (void)createVideoTrack
{
    NSArray<AVCaptureDevice *> *captureDevices = [RTCCameraVideoCapturer captureDevices];
    AVCaptureDevicePosition position = _usingFrontCamera ? AVCaptureDevicePositionFront : AVCaptureDevicePositionBack;
    AVCaptureDevice *device = captureDevices[0];
    for (AVCaptureDevice *obj in captureDevices) {
        if (obj.position == position) {
            device = obj;
            break;
        }
    }
    //检测摄像头权限
    AVAuthorizationStatus authStatus = [AVCaptureDevice authorizationStatusForMediaType:AVMediaTypeVideo];
    if(authStatus == AVAuthorizationStatusRestricted || authStatus == AVAuthorizationStatusDenied){
        NSLog(@"相机访问受限");
    }else{
        if (device) {
            RTCVideoSource *videoSource = [self.mPeerConnectionFactory videoSource];
            if (!_mVideoCapturer) {
                _mVideoCapturer = [[RTCCameraVideoCapturer alloc] initWithDelegate:videoSource];
                if ([_mVideoCapturer.captureSession canSetSessionPreset:AVCaptureSessionPresetLow]) {
                    [_mVideoCapturer.captureSession setSessionPreset:AVCaptureSessionPresetLow];
                }
            }
            if (!_videoTrack) {
                _videoTrack = [self.mPeerConnectionFactory videoTrackWithSource:videoSource trackId:VIDEO_TRACK_ID];
                _videoTrack.isEnabled = YES;
            }
            AVCaptureDeviceFormat *format = [[RTCCameraVideoCapturer supportedFormatsForDevice:device] lastObject];
            CGFloat fps = [[format videoSupportedFrameRateRanges] firstObject].maxFrameRate;
            [_mVideoCapturer startCaptureWithDevice:device format:format fps:fps];
            if (_delegate && [_delegate respondsToSelector:@selector(klPeerLocal:capturerSession:)]) {
                [_delegate klPeerLocal:self capturerSession:_mVideoCapturer.captureSession];
            }
        }
        else {
            NSLog(@"该设备不能打开摄像头");
        }
    }
    
    
}

/**停止视频采集*/
- (void)stopVideoTrack
{
    if (_mVideoCapturer) {
        [_mVideoCapturer stopCapture];
    }
}

/**媒体描述约束*/
- (RTCMediaConstraints *)defaultConstraint
{
    NSLog(@"");
    NSDictionary *mandatory = @{kRTCMediaConstraintsOfferToReceiveAudio : kRTCMediaConstraintsValueTrue,
                                kRTCMediaConstraintsOfferToReceiveVideo : kRTCMediaConstraintsValueTrue};
    RTCMediaConstraints *constraints = [[RTCMediaConstraints alloc] initWithMandatoryConstraints:mandatory optionalConstraints:nil];
    return constraints;
}

/**发送ICE给信令服务器*/
- (void)sendLocalIceCandidate:(RTCIceCandidate *)candidate
{
    NSDictionary *dic = @{@"candidate":@{@"type":@"candidate",@"label":@(candidate.sdpMLineIndex),@"id":candidate.sdpMid,@"candidate":candidate.sdp}};
    [self.mKLClient sendIceCandidate:self.roomId mid: self.streamId object:dic bPub:true];
}

/**设置视频参数*/
- (void)setVideoBitrate
{
    NSLog(@"");
    if (!_mPeerConnection || !_localViewSender) {
        return;
    }
    RTCRtpParameters *parameters = _localViewSender.parameters;
    if (parameters.encodings.count == 0) {
        return;
    }
    [parameters.encodings enumerateObjectsUsingBlock:^(RTCRtpEncodingParameters * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        //最小码率
//        obj.minBitrateBps = [NSNumber numberWithInt:200 * 1000];
        //最大码率
        obj.maxBitrateBps = [NSNumber numberWithInt:700 * 1000];
        //最大帧率
//        obj.maxFramerate  = [NSNumber numberWithInt:15];
    }];
}

#pragma mark - Getter

- (NSMutableArray *)mIceCandidates
{
    if (!_mIceCandidates) {
        _mIceCandidates = [NSMutableArray array];
    }
    return _mIceCandidates;
}


@end
